//! High level MIR module data.

use stencil_util::{FunctionName, ModuleName, TypeName};

use super::{function::MirFunction, ContainerData};

pub struct MirModule {
    name: ModuleName,
    containers: Vec<ModContainerEntry>,
}

impl MirModule {
    pub fn new(name: ModuleName, containers: Vec<ModContainerEntry>) -> Self {
        Self { name, containers }
    }

    pub fn name(&self) -> &ModuleName {
        &self.name
    }

    pub fn containers(&self) -> &[ModContainerEntry] {
        &self.containers
    }
}

/// Definition for a container within a module.
pub struct ModContainerEntry {
    /// Type name.
    name: TypeName,

    /// The type layout of the container.
    data: ContainerData,

    /// Functions on the container.
    functions: Vec<ContFunctionEntry>,
}

impl ModContainerEntry {
    pub fn new(name: TypeName, data: ContainerData, functions: Vec<ContFunctionEntry>) -> Self {
        Self {
            name,
            data,
            functions,
        }
    }

    pub fn name(&self) -> &TypeName {
        &self.name
    }

    pub fn data(&self) -> &ContainerData {
        &self.data
    }

    pub fn functions(&self) -> &[ContFunctionEntry] {
        &self.functions
    }

    pub fn find_function(&self, name: &FunctionName) -> Option<&MirFunction> {
        self.functions
            .iter()
            .find(|e| e.name() == name)
            .map(|e| &e.imp)
    }
}

/// A function on a container.
pub struct ContFunctionEntry {
    name: FunctionName,
    imp: MirFunction,
}

impl ContFunctionEntry {
    pub fn new(name: FunctionName, imp: MirFunction) -> Self {
        Self { name, imp }
    }

    pub fn name(&self) -> &FunctionName {
        &self.name
    }

    pub fn imp(&self) -> &MirFunction {
        &self.imp
    }
}
